import 'package:flutter/material.dart';
import 'dart:math';

class PathMetricsApplication extends StatefulWidget {
  @override
  _PathMetricsApplicationState createState() => _PathMetricsApplicationState();
}

class _PathMetricsApplicationState extends State<PathMetricsApplication>
    with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  void initState() {
    super.initState();
    controller =
        AnimationController(duration: const Duration(seconds: 2), vsync: this);
    animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation(
      parent: controller,
      curve: Curves.easeInOutSine,
    ))
      ..addListener(() {
        setState(() {});
      });
    // ..addStatusListener((status) {
    //   if (status == AnimationStatus.completed) {
    //     controller.reverse();
    //   } else if (status == AnimationStatus.dismissed) {
    //     controller.forward();
    //   }
    // });
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        child: CustomPaint(
          painter: PathMetricsApplicationPainter(
            animationValue: animation.value,
          ),
        ),
        onTap: () {
          controller.repeat();
          // if (controller.status == AnimationStatus.completed) {
          //   controller.reverse();
          // } else {
          //   controller.forward();
          // }
          // if (controller.isDismissed) {
          //   controller.forward();
          // }
        });
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

class PathMetricsApplicationPainter extends CustomPainter {
  final double animationValue;
  PathMetricsApplicationPainter({required this.animationValue});

  @override
  void paint(Canvas canvas, Size size) {
    //动画曲线：Curves.slowMiddle，控制器使用 repeat 模式
    //_drawLoadingCircle(canvas, size);
    //动画曲线：Curves.easeInOutQuart,控制器结束后使用 reverse 回到原位
    //_drawPendulum(canvas, size);
    //动画曲线：Curves.linear，控制器使用 repeat 模式
    _drawTwinsCircle(canvas, size);
  }

  _drawLoadingCircle(Canvas canvas, Size size) {
    var paint = Paint()
      ..style = PaintingStyle.stroke
      ..color = Colors.blue[400]!
      ..strokeWidth = 2.0;

    var path = Path();
    final radius = 40.0;
    var center = Offset(size.width / 2, size.height / 2);
    path.addOval(Rect.fromCircle(center: center, radius: radius));
    canvas.drawPath(path, paint);

    var innerPath = Path();
    final ballRadius = 4.0;
    innerPath
        .addOval(Rect.fromCircle(center: center, radius: radius - ballRadius));
    var metrics = innerPath.computeMetrics();
    paint.color = Colors.red;
    paint.style = PaintingStyle.fill;

    for (var pathMetric in metrics) {
      var tangent =
          pathMetric.getTangentForOffset(pathMetric.length * animationValue);

      canvas.drawCircle(tangent!.position, ballRadius, paint);
    }
  }

  _drawPendulum(Canvas canvas, Size size) {
    var paint = Paint()
      ..style = PaintingStyle.stroke
      ..color = Colors.blue[400]!
      ..strokeWidth = 2.0;

    final ceilWidth = 60.0;
    final pendulumHeight = 200.0;
    var ceilCenter =
        Offset(size.width / 2, size.height / 2 - pendulumHeight / 2);
    var ceilPath = Path()
      ..moveTo(ceilCenter.dx - ceilWidth / 2, ceilCenter.dy)
      ..lineTo(ceilCenter.dx + ceilWidth / 2, ceilCenter.dy);
    canvas.drawPath(ceilPath, paint);

    var pendulumArcPath = Path()
      ..addArc(Rect.fromCircle(center: ceilCenter, radius: pendulumHeight),
          3 * pi / 4, -pi / 2);

    paint.color = Colors.white70;
    var metrics = pendulumArcPath.computeMetrics();

    for (var pathMetric in metrics) {
      var tangent =
          pathMetric.getTangentForOffset(pathMetric.length * animationValue);

      canvas.drawLine(ceilCenter, tangent!.position, paint);
      paint.style = PaintingStyle.fill;
      paint.color = Colors.blue;
      paint.maskFilter = MaskFilter.blur(BlurStyle.solid, 4.0);
      canvas.drawCircle(tangent.position, 16.0, paint);
    }
  }

  _drawTwinsCircle(Canvas canvas, Size size) {
    var paint = Paint()
      ..style = PaintingStyle.stroke
      ..color = Colors.blue[400]!
      ..strokeWidth = 2.0;

    final radius = 50.0;
    final ballRadius = 6.0;
    var center = Offset(size.width / 2, size.height / 2);
    var circlePath = Path()
      ..addOval(Rect.fromCircle(center: center, radius: radius));
    paint.style = PaintingStyle.stroke;
    paint.color = Colors.blue[400]!;
    canvas.drawPath(circlePath, paint);

    var circleMetrics = circlePath.computeMetrics();
    for (var pathMetric in circleMetrics) {
      var tangent = pathMetric
          .getTangentForOffset(pathMetric.length * (1 - animationValue));

      paint.style = PaintingStyle.fill;
      paint.color = Colors.blue;
      canvas.drawCircle(tangent!.position, ballRadius, paint);
    }

    paint.style = PaintingStyle.stroke;
    paint.color = Colors.green[600]!;
    var ovalPath = Path()
      ..addOval(Rect.fromCenter(center: center, width: 3 * radius, height: 40));
    canvas.drawPath(ovalPath, paint);
    var ovalMetrics = ovalPath.computeMetrics();

    for (var pathMetric in ovalMetrics) {
      var tangent =
          pathMetric.getTangentForOffset(pathMetric.length * animationValue);

      paint.style = PaintingStyle.fill;
      canvas.drawCircle(tangent!.position, ballRadius, paint);
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
